package cplexSolve;

import ilog.concert.IloException;
import ilog.concert.IloIntVar;
import ilog.concert.IloLinearNumExpr;
import ilog.cplex.IloCplex;

import java.io.File;
import java.io.FileNotFoundException;
import java.util.Scanner;

public class FreightConsolidation {
	
	static int ORDER;
	static int ITEM;
	static int ROUTE;
	static int DATERANGE;
	static int T;
	static int indOrder[];
	static int indType[];
	static int indRoute[];
	static int indStart[];
	static int indShipDay[];
	static double v[];
	static double r[][];
	static double p[][];
	static double V[];
	static double tv;
	static int bin;
	static int C;
	static int arriveDate[];
	static int deadline[];
	static int shipTime[];
	static int startTime[][];
	static int shipDays;
	
	public static void main(String args[]) {
		Scanner scan = null;
		try {
			scan = new Scanner(new File("./packingData/data_O80A08R5U2/0.in"));
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		}
		
		ORDER = scan.nextInt();
		ITEM = scan.nextInt();
		ROUTE = scan.nextInt();
		DATERANGE = scan.nextInt();
		T = scan.nextInt();
		
		int i, j, k, l;
		indOrder = new int [ITEM];
		v = new double [ITEM];
		tv = 0;
		for (i = 0; i < ITEM; i++) {
			indOrder[i] = scan.nextInt();
			v[i] = scan.nextDouble();
			tv += v[i];
		}

		arriveDate = new int [ORDER];
		deadline = new int [ORDER];
		for (i = 0; i < ORDER; i++) {
			arriveDate[i] = scan.nextInt();
			deadline[i] = scan.nextInt();
		}
		
		r = new double [ITEM][ROUTE];
		for (i = 0; i < ITEM; i++) {
			for (j = 0; j < ROUTE; j++) {
				r[i][j] = scan.nextDouble();
			}
		}
		
		p = new double [T][ROUTE];
		for (i = 0; i < ROUTE; i++) {
			for (j = 0; j < T; j++) {
				p[j][i] = scan.nextDouble();
			}
		}
		
		shipTime = new int [ROUTE];
		for (i = 0; i < ROUTE; i++) {
			shipTime[i] = scan.nextInt();
		}
		
		shipDays = DATERANGE / 7 + 2;
		startTime = new int [ROUTE][shipDays];
		for (i = 0; i < ROUTE; i++) {
			for (j = 0; j < shipDays; j++) {
				startTime[i][j] = scan.nextInt();
			}
		}
		
		V = new double [T];
		C = 0;
		for (i = 0; i < T; i++) {
			V[i] = scan.nextDouble();
			C += ((int)(tv / V[i]) + 1) * ROUTE * shipDays;
		}

		indType = new int [C];
		indRoute = new int [C];
		indStart = new int [C];
		indShipDay = new int [C];

		C = 0;
		for (j = 0; j < ROUTE; j++) {
			for(k = 0; k < shipDays; k++) {
				for (i = 0; i < T; i++) {
					bin = (int)(tv / V[i]) + 1;
					for (l = 0; l < bin; l++) {
						indType[C] = i;
						indRoute[C] = j;
						indStart[C] = startTime[j][k];
						indShipDay[C] = k;
						C++;
					}
				}
			}
		}
		
		try {
			IloCplex cplex = new IloCplex();
			IloLinearNumExpr expr = cplex.linearNumExpr();
			IloIntVar x[][] = new IloIntVar [ITEM][C];
			IloIntVar y[] = new IloIntVar [C];
			IloIntVar z[][][] = new IloIntVar [ORDER][ROUTE][shipDays];
			
	        cplex.setParam(IloCplex.DoubleParam.EpGap, 1e-12);
			cplex.setParam(IloCplex.IntParam.NodeFileInd, 3);
			cplex.setParam(IloCplex.DoubleParam.WorkMem, 3072);
			cplex.setParam(IloCplex.StringParam.WorkDir, "C:/test");
			cplex.setParam(IloCplex.DoubleParam.TiLim, 3600);
//			cplex.setParam(IloCplex.DoubleParam.TreLim, 60);
			cplex.setParam(IloCplex.IntParam.VarSel, 3);
			cplex.setParam(IloCplex.IntParam.NodeSel, 0);
			
			for (i = 0; i < C; i++) {
				y[i] = cplex.boolVar();
			}
			for (i = 0; i < ITEM; i++) {
				for (j = 0; j < C; j++) {
					x[i][j] = cplex.boolVar();
				}
			}
			for (j = 0; j < ORDER; j++) {
				for (k = 0; k < ROUTE; k++) {
					for (i = 0; i < shipDays; i++) {
						z[j][k][i] = cplex.boolVar();
					}
				}
			}

			// Objective
			expr.clear();
			for (j = 0; j < C; j++) {
				expr.addTerm(p[indType[j]][indRoute[j]], y[j]);
			}
			for (i = 0; i < ITEM; i++) {
				for (j = 0; j < C; j++) {
					expr.addTerm(r[i][indRoute[j]], x[i][j]);
				}
			}
			cplex.addMinimize(expr);

			// Constraint 1
			for (i = 0; i < ITEM; i++) {
				expr.clear();
				for (j = 0; j < C; j++) {
					expr.addTerm(1, x[i][j]);
				}
				cplex.addEq(expr, 1);
			}

			// Constraint 2
			for (i = 0; i < ITEM; i++) {
				for (j = 0; j < C; j++) {
					cplex.addLe(x[i][j], y[j]);
				}
			}

			// Constraint 3
			for (i = 0; i < ITEM; i++) {
				for (j = 0; j < C; j++) {
					cplex.addLe(x[i][j], z[indOrder[i]][indRoute[j]][indShipDay[j]]);
				}
			}

			// Constraint 4
			for (k = 0; k < ORDER; k++) {
				expr.clear();
				for (l = 0; l < ROUTE; l++) {
					for (i = 0; i < shipDays; i++) {
						expr.addTerm(1, z[k][l][i]);
					}
				}
				cplex.addEq(expr, 1);
			}

			// Constraint 5
			for (j = 0; j < C; j++) {
				expr.clear();
				for (i = 0; i < ITEM; i++) {
					expr.addTerm(v[i], x[i][j]);
				}
				cplex.addLe(expr, V[indType[j]]);
			}

			// Constraint 6
			for (i = 0; i < ITEM; i++) {
				for (j = 0; j < C; j++) {
					expr.clear();
					expr.addTerm(arriveDate[indOrder[i]], x[i][j]);
					cplex.addLe(expr, indStart[j]);
				}
			}
			
			// Constraint 7
			for (i = 0; i < ITEM; i++) {
				for (j = 0; j < C; j++) {
					expr.clear();
					expr.addTerm(indStart[j] + shipTime[indRoute[j]], x[i][j]);
					cplex.addLe(expr, arriveDate[indOrder[i]] + deadline[indOrder[i]]);
				}
			}
			
			long st = System.currentTimeMillis();
			if (cplex.solve()) {
				cplex.output().println("Solution status = " + cplex.getStatus());
				cplex.output().println("Solution value = " + cplex.getObjValue());
				long ed = System.currentTimeMillis();
				System.out.println("Time: " + (ed - st) / 1000);

				System.out.println();
				System.out.println("Total Volume: " + tv);
				int container[][] = new int [T][ROUTE];
				for (j = 0; j < C; j++) {
					if (cplex.getValue(y[j]) > 0.9) container[indType[j]][indRoute[j]]++;
				}

				for (j = 0; j < ROUTE; j++) {
					for (i = 0; i < T; i++) {
						if (container[i][j] > 0) {
							System.out.println("Route " + j + " used " + container[i][j] +
									" containers of volume " + V[i] + ".");
						}
					}
				}

				for (i = 0; i < ITEM; i++) {
					for (j = 0; j < C; j++) {
						if (cplex.getValue(x[i][j]) > 0.9) {
							System.out.println("Order: " + indOrder[i] + "\tItem:  " + i 
									+ "\tRoute: " + indRoute[j] + "\tContainer: " + indType[j] +
									"\tArriveDate: " + arriveDate[indOrder[i]] + "\tDeadline: " + deadline[indOrder[i]] +
									"\tShipdate: " + indStart[j] + "\tTime: " + shipTime[indRoute[j]]);
						}
					}
				}
			}

			cplex.end();
		} catch (IloException e) {
			e.printStackTrace();
		}
	}
}
